﻿/* * * * * * * * * * * * * * * *
 * SDL ToolBox                 *
 * Copyright (c) VosSoft 2009  *
 * * * * * * * * * * * * * * * *
 * file:    form main          *
 * date:    2009-05-08         *
 * * * * * * * * * * * * * * * */

using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;

namespace SDL_ToolBox
{
    public partial class frmMain : Form
    {
        private const int PADDING = 6; // Rand bei den PictureBoxen - 3px rundrum

        private Config config;                                                                 // Konfigurationsdatei
        private Dictionary<string, string[]> categories = new Dictionary<string, string[]>();  // Texturenliste und deren Kategorien
        private Dictionary<string, Map> textures = new Dictionary<string, Map>();              // Texturenliste
        private Map map = new Map();                                                           // aktuelle Map
        private Texture selTexture = new Texture();                                            // markierte Texturenbereich
        private List<Texture[]> undoList = new List<Texture[]>(100);                           // undo-Liste mit maximal 100 Elementen
        private int undoPosition = -1;                                                         // undo-Position initialisieren
        private Pen selectionPen;                                                              // Auswahlrahmen
        private int selectionMode = 0, selectionModeX = -1, selectionModeY = -1;               // Auswahlmodus der Textur
        private int positionMode = 0, positionModeX = -1, positionModeY = -1;                  // Positionsmodus und Koordinaten der Map

        #region frmMain

        public frmMain()
        {
            InitializeComponent();

            // Ereignisse hinzufügen
            this.FormClosed += new FormClosedEventHandler(frmMain_FormClosed);
            this.picTextureSelection.MouseMove += new System.Windows.Forms.MouseEventHandler(this.picTextureSelection_MouseMove);
            this.picTextureSelection.MouseDown += new System.Windows.Forms.MouseEventHandler(this.picTextureSelection_MouseDown);
            this.picMapSelection.MouseMove += new System.Windows.Forms.MouseEventHandler(this.picMapSelection_MouseMove);
            this.picMapSelection.MouseDown += new System.Windows.Forms.MouseEventHandler(this.picMapSelection_MouseDown);

            // die Rangordnung der PictureBoxen ändern
            // Texture > Grid > Selection
            picTexture.Controls.Add(picTextureGrid);
            picTextureGrid.Controls.Add(picTextureSelection);
            // Background > Layer 1 > Layer 2 > Foreground > Grid > Selection
            picMapBackground.Controls.Add(picMapLayer1);
            picMapLayer1.Controls.Add(picMapLayer2);
            picMapLayer2.Controls.Add(picMapForeground);
            picMapForeground.Controls.Add(picMapGrid);
            picMapGrid.Controls.Add(picMapSelection);
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            try
            {
                string configFile = Path.Combine(Application.StartupPath, "config.xml");
                config = new Config(configFile);
                if (File.Exists(configFile) == false)
                {
                    config.Create(Application.StartupPath);
                }
                config.Load(true);
                // Fenster-Einstellungen laden
                Left = Convert.ToInt32(config.Sections[Name].Settings["left"].Value);
                Top = Convert.ToInt32(config.Sections[Name].Settings["top"].Value);
                Width = Convert.ToInt32(config.Sections[Name].Settings["width"].Value);
                Height = Convert.ToInt32(config.Sections[Name].Settings["height"].Value);
                WindowState = ToolBox.getWindowState(config.Sections[Name].Settings["windowState"].Value);

                // Auswahlrahmen definieren
                selectionPen = new Pen(Color.FromArgb(Convert.ToInt32(config.Sections["selection"].Settings["alpha"].Value),
                    Color.FromArgb(Convert.ToInt32(config.Sections["selection"].Settings["color"].Value))),
                    Convert.ToInt32(config.Sections["selection"].Settings["width"].Value));
                selectionPen.DashStyle = ToolBox.getDashStyle(config.Sections["selection"].Settings["style"].Value);

                // Layer auf "beide" setzen
                cmbLayer.SelectedIndex = 0;

                status.Text = "SDL ToolBox wurde erfolgreich geladen. ACHTUNG -> beta Version ;-)";

                // Thread für die Performanceanzeige erstellen und starten
                Thread performanceThread = new Thread(new ThreadStart(getCurrentPerformance));
                performanceThread.IsBackground = true;
                performanceThread.Start();
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message, "Fehler beim Laden des Formulars", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void frmMain_FormClosed(object sender, EventArgs e)
        {
            try
            {
                // Fenster-Einstellungen speichern
                if (WindowState == FormWindowState.Normal)
                {
                    config.Sections[Name].Settings["left"].Value = Left.ToString();
                    config.Sections[Name].Settings["top"].Value = Top.ToString();
                    config.Sections[Name].Settings["width"].Value = Width.ToString();
                    config.Sections[Name].Settings["height"].Value = Height.ToString();
                }
                config.Sections[Name].Settings["windowState"].Value = WindowState.ToString();
                config.Save();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Fehler beim Beenden", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Application.Exit();
            }
        }

        #endregion

        #region Menü

        private void neuToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int x = Convert.ToInt32(config.Sections["map"].Settings["x"].Value);
            int y = Convert.ToInt32(config.Sections["map"].Settings["y"].Value);
            int size = Convert.ToInt32(config.Sections["map"].Settings["size"].Value);
            if (textures.Count > 0)
            {
                // wenn keine Textur ausgewählt wurde
                if (selTexture.Size == 0)
                {
                    // benutze Textur[0,0] als Hintergrund für die Map
                    selTexture = textures[cmbTextures.SelectedItem.ToString()].Layer1[0, 0];
                }
                map = new Map("neu", x, y, size, config.Sections["map"].Settings["background"].Value.ToCharArray(), config.Sections["map"].Settings["foreground"].Value.ToCharArray(), selTexture);
                grpMap.Top = grpTexture.Top + grpTexture.Height + 6;
                grpMap.Width = x * size + PADDING;
                grpMap.Height = y * size + PADDING + 13;
                chkBackground_CheckedChanged(sender, e);
                MapRefresh(cmbLayer.SelectedIndex, true);
                status.Text = "Die Map(" + x + " x " + y + ", Size = " + size + ") wurde erstellt.";
            }
            else
            {
                MessageBox.Show("Bitte zuerst Texturen laden.", "Texturen fehlen", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void öffnenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dlgOpen.Title = "Map öffnen";
            dlgOpen.DefaultExt = "evm";
            dlgOpen.Filter = "Evil-Map Dateien (*.evm)|*.evm|Alle Dateien (*.*)|*.*";
            dlgOpen.InitialDirectory = config.Sections["map"].Settings["path"].Value;
            if (dlgOpen.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    map = new Map();
                    map.Read(dlgOpen.FileName, textures);
                    grpMap.Top = grpTexture.Top + grpTexture.Height + 6;
                    grpMap.Width = map.X * map.Size + PADDING;
                    grpMap.Height = map.Y * map.Size + PADDING + 13;
                    chkBackground_CheckedChanged(sender, e);
                    MapRefresh(cmbLayer.SelectedIndex, true);
                    status.Text = "Die Map \"" + Path.GetFileName(map.Name) + "\" wurde geladen.";
                }
                catch (KeyNotFoundException ex)
                {
                    map = new Map();
                    MessageBox.Show(ex.Message, "Fehler beim Öffnen der Map", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    status.Text = "Die Map \"" + Path.GetFileName(map.Name) + "\" konnte nicht geladen werden!";
                }
            }
        }

        private void speichernToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (map.Size > 0)
            {
                if (map.Name == "neu")
                {
                    speichernunterToolStripMenuItem_Click(sender, e);
                }
                else
                {
                    if (File.Exists(map.Name))
                    {
                        if (MessageBox.Show("Die Datei \"" + map.Name + "\" existiert schon, soll sie überschrieben werden?", "Map überschreiben", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                        {
                            map.Write(map.Name);
                            status.Text = "Die Map \"" + Path.GetFileName(map.Name) + "\" wurde gespeichert.";
                        }
                    }
                    else
                    {
                        map.Write(map.Name);
                        status.Text = "Die Map \"" + Path.GetFileName(map.Name) + "\" wurde gespeichert.";
                    }
                }
            }
        }

        private void speichernunterToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dlgSave.Title = "Map speichern";
            dlgSave.DefaultExt = "evm";
            dlgSave.Filter = "Evil-Map Dateien (*.evm)|*.evm";
            dlgSave.InitialDirectory = config.Sections["map"].Settings["path"].Value;
            if (dlgSave.ShowDialog() == DialogResult.OK)
            {
                map.Name = dlgSave.FileName;
                speichernToolStripMenuItem_Click(sender, e);
            }
        }

        private void beendenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void undoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            undoListUndo();
        }

        private void redoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            undoListRedo();
        }

        private void optionenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmEinstellungen einstellungen = new frmEinstellungen(config, map);
            einstellungen.Show();
        }

        private void infoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show(frmMain.ActiveForm.Text + "\n\nMap Editor - still in progress ;-)", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        #endregion

        #region Toolbar

        private void neuToolStripButton_Click(object sender, EventArgs e)
        {
            neuToolStripMenuItem_Click(sender, e);
        }

        private void öffnenToolStripButton_Click(object sender, EventArgs e)
        {
            öffnenToolStripMenuItem_Click(sender, e);
        }

        private void speichernToolStripButton_Click(object sender, EventArgs e)
        {
            speichernToolStripMenuItem_Click(sender, e);
        }

        private void undoToolStripButton_Click(object sender, EventArgs e)
        {
            undoToolStripMenuItem_Click(sender, e);
        }

        private void redoToolStripButton_Click(object sender, EventArgs e)
        {
            redoToolStripMenuItem_Click(sender, e);
        }

        private void hilfeToolStripButton_Click(object sender, EventArgs e)
        {
            infoToolStripMenuItem_Click(sender, e);
        }

        #endregion

        #region Einstellungen

        private void btnTexLoad_Click(object sender, EventArgs e)
        {
            btnTexLoad.Enabled = false;
            try
            {
                if (File.Exists(Path.Combine(config.Sections["textures"].Settings["path"].Value, "index.xml")))
                {
                    DataSet texList = new DataSet();
                    DataRow[] dsCategories, dsTextures, dsTexturesCat;
                    texList.ReadXml(Path.Combine(config.Sections["textures"].Settings["path"].Value, "index.xml"));
                    if (Directory.Exists(config.Sections["textures"].Settings["path"].Value))
                    {
                        dsTextures = texList.Tables[0].Select("load = true", "name");
                        if (dsTextures.Length > 0)
                        {
                            Image img;
                            Stopwatch uhr = new Stopwatch();
                            string texName, catName, catIds = "";
                            int n, width, height;
                            categories.Clear();
                            textures.Clear();
                            cmbCategories.Items.Clear();
                            cmbTextures.Items.Clear();
                            //GC.Collect();
                            uhr.Reset();
                            uhr.Start();
                            for (int i = 0; i < dsTextures.Length; i++)
                            {
                                status.Text = "Texturen werden geladen... " + (i + 1) + "/" + dsTextures.Length;
                                Refresh();
                                texName = dsTextures[i].ItemArray[0].ToString();
                                n = Convert.ToInt32(dsTextures[i].ItemArray[1]);
                                catIds += dsTextures[i].ItemArray[4].ToString() + ",";
                                img = Image.FromFile(Path.Combine(config.Sections["textures"].Settings["path"].Value, texName));
                                width = img.Width / n;
                                height = img.Height / n;
                                textures.Add(texName, new Map(Path.Combine(config.Sections["textures"].Settings["path"].Value, texName), width, height, n));
                                textures[texName].LoadTexturesFromImage(img, n, progress);
                                // colorkey zuweisen
                                for (int y = 0; y < height; y++)
                                {
                                    for (int x = 0; x < width; x++)
                                    {
                                        textures[texName].Layer1[x, y].setRGB(Convert.ToInt32(dsTextures[i].ItemArray[2]));
                                        textures[texName].Layer1[x, y].Bmp.MakeTransparent(Color.FromArgb(Convert.ToInt32(dsTextures[i].ItemArray[2])));
                                    }
                                }
                            }
                            catIds = catIds.Substring(0, catIds.Length - 1);
                            dsCategories = texList.Tables[1].Select(String.Format("NOT name = '' AND cid IN({0})", catIds), "name");
                            for (int i = 0; i < dsCategories.Length; i++)
                            {
                                dsTexturesCat = texList.Tables[0].Select(String.Format("load = true AND cid = {0}", dsCategories[i].ItemArray[0].ToString()), "name");
                                catName = dsCategories[i].ItemArray[1].ToString();
                                categories.Add(catName, new string[dsTexturesCat.Length]);
                                cmbCategories.Items.Add(catName);
                                for (int j = 0; j < dsTexturesCat.Length; j++)
                                {
                                    categories[catName][j] = dsTexturesCat[j].ItemArray[0].ToString();
                                }
                            }
                            uhr.Stop();
                            status.Text = "Es wurden " + dsTextures.Length + " Texturen geladen (" + System.Math.Round((double)uhr.ElapsedMilliseconds / 1000, 2) + " s).";
                            cmbCategories.SelectedIndex = 0;
                        }
                        else
                        {
                            MessageBox.Show("Es wurden keine Texturen zum Laden ausgewählt", "Keine Textur geladen", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        }
                    }
                    else
                    {
                        MessageBox.Show("Das Verzeichnis \"" + config.Sections["textures"].Settings["path"].Value + "\" konnte nicht geöffnet werden.", "Verzeichnis existiert nicht", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                else
                {
                    MessageBox.Show("Die Texturen-DB \"" + Path.Combine(config.Sections["textures"].Settings["path"].Value, "index.xml") + "\" konnte nicht geöffnet werden.\n\nBitte gehe über das Hauptmenü unter \"Extras -> Optionen -> Texturen\" und öffne oder erstelle dort zuerst eine Texturen-DB. :-)", "Texturen-DB nicht gefunden", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Fehler beim Laden der Texturen", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            btnTexLoad.Enabled = true;
        }

        private void chkGrid_CheckedChanged(object sender, EventArgs e)
        {
            if (textures.Count > 0 && map.Size > 0)
            {
                if (chkGrid.Checked == true)
                {
                    int size;
                    Bitmap bmp;
                    Graphics graph;
                    Pen pen = new Pen(Color.FromArgb(Convert.ToInt32(config.Sections["grid"].Settings["alpha"].Value),
                        Color.FromArgb(Convert.ToInt32(config.Sections["grid"].Settings["color"].Value))),
                        Convert.ToInt32(config.Sections["grid"].Settings["width"].Value));
                    pen.DashStyle = ToolBox.getDashStyle(config.Sections["grid"].Settings["style"].Value);

                    // Raster Textur
                    size = textures[cmbTextures.SelectedItem.ToString()].Size;
                    bmp = new Bitmap(picTextureGrid.Width, picTextureGrid.Height);
                    graph = Graphics.FromImage(bmp);
                    for (int i = size; i < bmp.Height - 1; i += size)
                        graph.DrawLine(pen, 0, i, bmp.Width, i);
                    for (int i = size; i < bmp.Width - 1; i += size)
                        graph.DrawLine(pen, i, 0, i, bmp.Height);
                    picTextureGrid.BackgroundImage = (Image)bmp.Clone();

                    // Raster Map
                    size = map.Size;
                    bmp = new Bitmap(picMapGrid.Width, picMapGrid.Height);
                    graph = Graphics.FromImage(bmp);
                    for (int i = size; i < bmp.Height - 1; i += size)
                        graph.DrawLine(pen, 0, i, bmp.Width, i);
                    for (int i = size; i < bmp.Width - 1; i += size)
                        graph.DrawLine(pen, i, 0, i, bmp.Height);
                    picMapGrid.BackgroundImage = (Image)bmp.Clone();

                    graph.Dispose();
                    bmp.Dispose();
                }
                else
                {
                    picTextureGrid.BackgroundImage = null;
                    picMapGrid.BackgroundImage = null;
                }
            }
            else
            {
                chkGrid.Checked = false;
            }
        }

        #endregion

        #region Texturenauswahl

        private void cmbCategories_SelectedIndexChanged(object sender, EventArgs e)
        {
            cmbTextures.Items.Clear();
            foreach (string item in categories[cmbCategories.SelectedItem.ToString()])
            {
                cmbTextures.Items.Add(item);
            }
            cmbTextures.SelectedIndex = 0;
        }

        private void cmbTextures_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                if (textures.Count > 0)
                {
                    Image img = Image.FromFile(textures[cmbTextures.SelectedItem.ToString()].Name);
                    grpTexture.Width = img.Width + PADDING;
                    grpTexture.Height = img.Height + PADDING + 13;
                    picTexture.BackgroundImage = img;
                    picCurrent.Width = textures[cmbTextures.SelectedItem.ToString()].Size;
                    picCurrent.Height = textures[cmbTextures.SelectedItem.ToString()].Size;
                    picSelected.Width = textures[cmbTextures.SelectedItem.ToString()].Size;
                    picSelected.Height = textures[cmbTextures.SelectedItem.ToString()].Size;
                    chkGrid_CheckedChanged(sender, e);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Fehler beim Laden der Textur", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion

        #region Layerauswahl

        private void cmbLayer_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (map.Size > 0)
            {
                if (cmbLayer.SelectedIndex == 1) // Layer 1
                {
                    lblLayer.Text = "Zeichnung auf Layer 1 (Hintergrund)";
                }
                else // Layer 2 oder beide
                {
                    lblLayer.Text = "Zeichnung auf Layer 2 (Vordergrund)";
                }
                MapRefresh(cmbLayer.SelectedIndex, true);
            }
            else
            {
                cmbLayer.SelectedIndex = 0;
            }
        }

        private void chkBackground_CheckedChanged(object sender, EventArgs e)
        {
            if (chkBackground.Checked == true)
            {
                if (map.Size > 0)
                {
                    string background = Path.Combine(config.Sections["resources"].Settings["path"].Value.ToString(), new String(map.Background).TrimEnd());
                    if (File.Exists(background) == true)
                    {
                        picMapBackground.BackgroundImage = Image.FromFile(background);
                    }
                    else
                    {
                        picMapBackground.BackgroundImage = null;
                        picMapBackground.BackColor = Color.White;
                        status.Text = "Das Hintergrundbild \"" + Path.GetFileName(background) + "\" wurde nicht im Ressourcenverzeichnis gefunden!";
                    }
                }
                else
                {
                    picMapBackground.BackgroundImage = null;
                    picMapBackground.BackColor = Color.White;
                }
            }
            else
            {
                picMapBackground.BackgroundImage = null;
                picMapBackground.BackColor = picBackgroundColor.BackColor;
            }
        }

        private void picBackgroundColor_Click(object sender, EventArgs e)
        {
            dlgColor.Color = picBackgroundColor.BackColor;
            dlgColor.ShowDialog();
            picBackgroundColor.BackColor = dlgColor.Color;
            chkBackground_CheckedChanged(sender, e);
        }

        #endregion

        #region Textur

        private void picTextureSelection_MouseMove(object sender, MouseEventArgs e)
        {
            if (textures.Count > 0)
            {
                int size = textures[cmbTextures.SelectedItem.ToString()].Size;
                int x = e.X / size;
                int y = e.Y / size;
                picCurrent.Image = textures[cmbTextures.SelectedItem.ToString()].Layer1[x, y].Bmp;
                lblCurrent.Text = "Textur: " + cmbTextures.SelectedItem.ToString() + " [ " + x + " | " + y + " ]";
            }
        }

        private void picTextureSelection_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && textures.Count > 0)
            {
                int size = textures[cmbTextures.SelectedItem.ToString()].Size;
                int x = e.X / size;
                int y = e.Y / size;
                selectionModeX = x;
                selectionModeY = y;
                positionModeX = -1;
                positionModeY = -1;
                TextureSelection(x, y, size, size, size);
            }
        }

        private void TextureSelection(int x, int y, int size, int width, int height)
        {
            if (x < 0)
            {
                x = 0;
            }
            if (y < 0)
            {
                y = 0;
            }
            if (picTexture.Width < x * size + width)
            {
                x = textures[cmbTextures.SelectedItem.ToString()].X - 1;
            }
            if (picTexture.Height < y * size + height)
            {
                y = textures[cmbTextures.SelectedItem.ToString()].Y - 1;
            }
            Bitmap bmp = new Bitmap(picTextureSelection.Width, picTextureSelection.Height);
            Graphics graph = Graphics.FromImage(bmp);
            graph.DrawRectangle(selectionPen, x * size, y * size, width, height);
            picTextureSelection.Image = bmp;
            graph.Dispose();
            selTexture = textures[cmbTextures.SelectedItem.ToString()].Layer1[x, y];
            picSelected.Image = selTexture.Bmp;
            lblSelected.Text = "Textur: " + cmbTextures.SelectedItem.ToString() + " [ " + x + " | " + y + " ]";
        }

        #endregion

        #region Textur Kontextmenü

        private void toolStripMenuItemBlock_Click(object sender, EventArgs e)
        {
            selectionMode = 0;
            toolStripMenuItemBlock.Checked = true;
            toolStripMenuItemRegion.Checked = false;
        }

        private void toolStripMenuItemRegion_Click(object sender, EventArgs e)
        {
            selectionMode = 1;
            toolStripMenuItemBlock.Checked = false;
            toolStripMenuItemRegion.Checked = true;
        }

        #endregion

        #region Map

        private void picMapSelection_MouseMove(object sender, MouseEventArgs e)
        {
            if (map.X > 0 && map.Y > 0 && map.Size > 0)
            {
                int size = map.Size;
                int x = e.X / size;
                int y = e.Y / size;
                if (positionMode == 1 && selectionModeX >= 0 && selectionModeY >= 0 && positionModeX >= 0 && positionModeY >= 0)
                {
                    TextureSelection(x - positionModeX + selectionModeX, y - positionModeY + selectionModeY, size, size, size);
                }
                if (cmbLayer.SelectedIndex == 1) // Layer 1
                {
                    picCurrent.Image = map.Layer1[x, y].Bmp;
                    lblCurrent.Text = "Map [ Layer 1 | " + x + " | " + y + " ]: \n" + new String(map.Layer1[x, y].Name).TrimEnd() + " [ " + map.Layer1[x, y].OffX + ", " + map.Layer1[x, y].OffY + " ]";
                }
                else // Layer 2 oder beide
                {
                    picCurrent.Image = map.Layer2[x, y].Bmp;
                    lblCurrent.Text = "Map [ Layer 2 | " + x + " | " + y + " ]: \n" + new String(map.Layer2[x, y].Name).TrimEnd() + " [ " + map.Layer2[x, y].OffX + ", " + map.Layer2[x, y].OffY + " ]";
                }
            }
        }

        private void picMapSelection_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && map.X > 0 && map.Y > 0 && selTexture.Size > 0)
            {
                int size = textures[cmbTextures.SelectedItem.ToString()].Size;
                int x = e.X / size;
                int y = e.Y / size;
                Texture[] undoEntry = new Texture[2];
                undoEntry[0] = new Texture();
                undoEntry[1] = new Texture();
                undoEntry[1].Copy(selTexture, false);
                if (positionModeX == -1 && positionModeY == -1)
                {
                    positionModeX = x;
                    positionModeY = y;
                }
                if (cmbLayer.SelectedIndex == 0) // beide Layer
                {
                    undoEntry[0].Copy(map.Layer2[x, y], true);
                    undoEntry[1].X = 2; // Layer speichern
                    map.Layer2[x, y].Copy(selTexture, false);
                    MapRefresh(2, false);
                }
                else
                {
                    if (cmbLayer.SelectedIndex == 1) // Layer 1
                    {
                        undoEntry[0].Copy(map.Layer1[x, y], true);
                        undoEntry[1].X = 1; // Layer speichern
                        map.Layer1[x, y].Copy(selTexture, false);
                        MapRefresh(1, false);
                    }
                    else // Layer 2
                    {
                        undoEntry[0].Copy(map.Layer2[x, y], true);
                        undoEntry[1].X = 2; // Layer speichern
                        map.Layer2[x, y].Copy(selTexture, false);
                        MapRefresh(2, false);
                    }
                }
                undoListAdd(undoEntry);
            }
        }

        /// <summary>
        /// Den Anzeigebereich der Map aktualisieren
        /// </summary>
        /// <param name="layer">Layerdarstellung (0 = beide, 1 = nur Layer 1, 2 = nur Layer 2)</param>
        /// <param name="refresh">Bild vorher löschen</param>
        private void MapRefresh(int layer, bool refresh)
        {
            if (map.Size > 0)
            {
                if (refresh == true)
                {
                    picMapLayer1.BackgroundImage = null;
                    picMapLayer2.BackgroundImage = null;
                    picMapLayer1.Refresh();
                    picMapLayer2.Refresh();
                }
                if (layer == 0 || layer == 1)
                {
                    picMapLayer1.BackgroundImage = map.GetImage(1);
                }
                if (layer == 0 || layer == 2)
                {
                    picMapLayer2.BackgroundImage = map.GetImage(2);
                }
            }
        }

        #endregion

        #region Map Kontextmenü

        private void toolStripMenuItemStandard_Click(object sender, EventArgs e)
        {
            positionMode = 0;
            positionModeX = -1;
            positionModeY = -1;
            toolStripMenuItemStandard.Checked = true;
            toolStripMenuItemCursor.Checked = false;
        }

        private void toolStripMenuItemCursor_Click(object sender, EventArgs e)
        {
            positionMode = 1;
            positionModeX = -1;
            positionModeY = -1;
            toolStripMenuItemStandard.Checked = false;
            toolStripMenuItemCursor.Checked = true;
        }

        #endregion

        #region Undo-Funktion

        private void undoListAdd(Texture[] undoEntry)
        {
            if (undoPosition >= 0) // undo wurde vorrher ausgeführt
            {
                undoList.RemoveRange(undoPosition, undoList.Count - undoPosition); // Liste ab undo-Position löschen
                undoPosition = -1;  // Positionsmarker zurück setzen
            }
            if (undoList.Count >= undoList.Capacity) // wenn die Liste "voll" ist
            {
                undoList.RemoveAt(0); // das 1. Element löschen
            }
            undoList.Add(undoEntry); // Element der undo-Liste hinzufügen
            undoToolStripMenuItem.Enabled = true;
            undoToolStripButton.Enabled = true;
            redoToolStripMenuItem.Enabled = false;
            redoToolStripButton.Enabled = false;
        }

        private void undoListUndo()
        {
            if (undoPosition == -1) // erster undo
            {
                undoPosition = undoList.Count - 1; // Startposition  (letztes Element der Liste)
                redoToolStripMenuItem.Enabled = true;
                redoToolStripButton.Enabled = true;
            }
            else
            {
                if (undoPosition > 0) // solange das Ende der Liste noch nicht erreicht ist
                {
                    undoPosition--; // bei jedem weiteren undo einen Schritt zurück gehen
                }
            }
            if (undoPosition == 0) // Anfang der Liste erreicht, kein weiterer undo-Schritt möglich
            {
                undoToolStripMenuItem.Enabled = false;
                undoToolStripButton.Enabled = false;
            }
            if (undoList[undoPosition][1].X == 1) // Layer 1
            {
                map.Layer1[undoList[undoPosition][0].X, undoList[undoPosition][0].Y].Copy(undoList[undoPosition][0], false);
                MapRefresh(1, false);
            }
            else // Layer 2
            {
                map.Layer2[undoList[undoPosition][0].X, undoList[undoPosition][0].Y].Copy(undoList[undoPosition][0], false);
                MapRefresh(2, false);
            }
        }

        private void undoListRedo()
        {
            if (undoList[undoPosition][1].X == 1) // Layer 1
            {
                map.Layer1[undoList[undoPosition][0].X, undoList[undoPosition][0].Y].Copy(undoList[undoPosition][1], false);
                MapRefresh(1, false);
            }
            else // Layer 2
            {
                map.Layer2[undoList[undoPosition][0].X, undoList[undoPosition][0].Y].Copy(undoList[undoPosition][1], false);
                MapRefresh(2, false);
            }
            if (undoPosition == undoList.Count - 1) // Ende der Liste erreicht
            {
                // alles zurück setzen
                undoPosition = -1;
                redoToolStripMenuItem.Enabled = false;
                redoToolStripButton.Enabled = false;
                undoToolStripMenuItem.Enabled = true;
                undoToolStripButton.Enabled = true;
                return;
            }
            if (undoPosition >= 0) // Schritt wiederholen
            {
                undoPosition++; // bei jedem redo einen Schritt vorwärts gehen
                undoToolStripMenuItem.Enabled = true;
                undoToolStripButton.Enabled = true;
            }
        }

        #endregion

        #region Thread Performanceanzeige

        private void getCurrentPerformance()
        {
            PerformanceCounter pcCPU = new PerformanceCounter("Process", "% Processor Time");
            PerformanceCounter pcRAM = new PerformanceCounter("Process", "Working Set");
            PerformanceCounter pcThreadCount = new PerformanceCounter("Process", "Thread Count");

            pcCPU.InstanceName = Process.GetCurrentProcess().ProcessName;
            pcRAM.InstanceName = Process.GetCurrentProcess().ProcessName;
            pcThreadCount.InstanceName = Process.GetCurrentProcess().ProcessName;

            float processorTime;
            float ramUsage;
            float threadCount;

            do
            {
                processorTime = pcCPU.NextValue(); // CPU-Auslastung in %
                ramUsage = pcRAM.NextValue() / 1048576; // RAM-Verbrauch in MB
                threadCount = pcThreadCount.NextValue(); // Anzahl der Threads

                statusRight.Text = "CPU: " + processorTime.ToString("0.00") + "% | RAM: " + ramUsage.ToString("0.00") + " MB | " + threadCount + " Threads";

                Thread.Sleep(1000);
            }
            while (true);
        }

        #endregion

    }
}
